package ru.compft.aop.profiling;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * User: ASUS
 * Date: 21.10.12
 * Time: 11:38
 * Компонент для профилирования
 */
@Component
@Aspect
public class DataAccessLayerProfiler {
    private static final Logger logger = LoggerFactory.getLogger(DataAccessLayerProfiler.class);

    @Before(value = "ru.compft.aop.SystemArchitecture.inDataAccessLayer()")
    public void doDataAccessLayerBefore() {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerBefore");
    }

    @Before(value = "ru.compft.aop.SystemArchitecture.dataAccessOperation()")
    public void doDataAccessOperationBefore() {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationBefore");
    }

    @Around("ru.compft.aop.SystemArchitecture.inDataAccessLayer()")
    public Object doDataAccessLayerProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    @Around("ru.compft.aop.SystemArchitecture.dataAccessOperation()")
    public Object doDataAccessOperationProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    /**
     * After (finally) advice runs however a matched method execution exits
     */
    @After("ru.compft.aop.SystemArchitecture.inDataAccessLayer()")
    public void doDataAccessLayerMethodAfter() {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerMethodAfter");
    }

    @After("ru.compft.aop.SystemArchitecture.dataAccessOperation()")
    public void doDataAccessOperationMethodAfter() {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationMethodAfter");
    }

    /**
     * Sometimes you need access in the advice body to the actual value that was returned
     *
     * @param retVal
     */
    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.inDataAccessLayer()",
            returning = "retVal")
    public void doDataAccessLayerAfterReturning(Object retVal) {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerAfterReturning. Obj = " + retVal);
        // ...
    }

    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.dataAccessOperation()",
            returning = "retVal")
    public void doDataAccessOperationAfterReturning(Object retVal) {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationAfterReturning. Obj = " + retVal);
        // ...
    }

    /**
     * After throwing advice runs when a matched method execution exits by throwing an exception
     */
    @AfterThrowing("ru.compft.aop.SystemArchitecture.inDataAccessLayer()")
    public void doDataAccessLayerAfterThrowing() {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerAfterThrowing");
        // ...
    }

    @AfterThrowing("ru.compft.aop.SystemArchitecture.dataAccessOperation()")
    public void doDataAccessOperationAfterThrowing() {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationAfterThrowing");
        // ...
    }

    /**
     * Often you want the advice to run only when exceptions of a given type are thrown, and you also often need access
     * to the thrown exception in the advice body
     *
     * @param ex
     */
    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.inDataAccessLayer()",
            throwing = "ex")
    public void doDataAccessLayerAfterThrowing(Exception ex) {
        System.out.println("DataAccessLayerProfiler doDataAccessLayerAfterThrowing. Ex = " + ex);
        // ...
    }

    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.dataAccessOperation()",
            throwing = "ex")
    public void doDataAccessOperationAfterThrowing(Exception ex) {
        System.out.println("DataAccessLayerProfiler doDataAccessOperationAfterThrowing. Ex = " + ex);
        // ...
    }
}
